Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.

...powered by www.netzwerkartist.de...

 <<   zurück
Visual Basic 2005 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual Basic 2005

Visual Basic 2005
1.233 S., mit 2 CDs, 59,90 Euro
Galileo Computing
ISBN 3-89842-585-1
gp Kapitel 13 Serialisierung
  gp 13.1 Einführung in die Serialisierung
    gp 13.1.1 Serialisierungsverfahren
  gp 13.2 Serialisierung mit »BinaryFormatter«
  gp 13.3 Serialisierung mit »SoapFormatter«
  gp 13.4 Serialisierung mit »XmlSerializer«
    gp 13.4.1 XML-Serialisierung mit Attributen steuern


Galileo Computing

13.2 Serialisierung mit »BinaryFormatter«  toptop

Ein Objekt unter .NET serialisierbar zu machen, ist geradezu genial einfach gelöst. Allerdings muss man sich schon bei der Entwicklung einer Klasse darüber klar sein, dass Objekte der Klasse dem Serialisierungsprozess zugeführt werden sollen. Dazu wird die Klasse nur mit dem Attribut Serializable markiert:


<Serializable()> Public Class ClassA
...
End Class

Fehlt das Attribut, wird die Ausnahme SerializationException ausgelöst. Alle Felder der Klasse ClassA, unabhängig davon, ob sie privat oder öffentlich deklariert sind, werden damit von der Serialisierung erfasst. Es gibt aber auch eine Einschränkung:


Lokale Variablen und statische Klassendaten nehmen nicht an einem Serialisierungsprozess teil.


Wir wollen nun die Klassendefinition komplettieren, um anhand eines einfachen Beispiels zu sehen, wie die Serialisierung angestoßen und später das serialisierte Objekt rekonstruiert wird. Dazu implementieren wir in der Klasse ClassA ein privates und ein öffentliches Feld, die beide über einen parametrisierten Konstruktor initialisiert werden.


<Serializable()> Class ClassA
Public intVar As Integer
Private strName As String
Public Sub New(ByVal x As Integer, ByVal str As String)
intVar = x
strName = str
End Sub
Public Property Name() As String
Get
Return strName
End Get
Set(ByVal value As String)
strName = value
End Set
End Property
End Class

Wird die Serialisierung angestoßen, greift sich der Prozess den Inhalt von intVar und strName und speichert ihn entweder in einer Datei, im Netzwerk oder in einer Datenbank.

Der Code, der ein Objekt vom Typ der Klasse ClassA serialisiert, könnte folgendermaßen aussehen:


Imports System.Runtime.Serialization.Formatters.Binary
...
Dim obj As ClassA = New ClassA(310, "Peter")
Dim myStream As FileStream
myStream = New FileStream("C:\MyObject.dat", FileMode.Create)
Dim binFormatter As BinaryFormatter = New BinaryFormatter()
binFormatter.Serialize(myStream, obj)
myStream.Close()

Im Code wird ein FileStream generiert, der die binäre Datei MyObject.dat anlegt oder, falls eine Datei dieses Namens bereits existiert, die alte überschreibt. Anschließend erzeugen wir ein Objekt vom Typ BinaryFormatter, dessen Methode Serialize wir unter Übergabe des Stream-Objekts und der zu serialisierenden Objektreferenz aufrufen.

Die Deserialisierung

Die Deserialisierung des gespeicherten Objekts ist genauso einfach. Beachtet werden muss dabei nur, dass der Rückgabewert vom Typ Object ist und deshalb noch in den richtigen Typ konvertiert werden muss.


Dim oldObj As ClassA
Dim binFormatter As New BinaryFormatter
Dim fs As FileStream = New FileStream("C:\MyObject.dat", FileMode.Open)
oldObj = binFormatter.Deserialize(fs)

Fassen wir nun den Code in einem Beispielprogramm zusammen. Serialisierung und Deserialisierung werden in je einer eigenen Methode behandelt, die aus Main heraus aufgerufen wird. Nach der Serialisierung des Objekts obj wird der neuen Objektvariablen oldObj der Rückgabewert der Deserialisierung zugewiesen. Zum Schluss werden die rekonstruierten Objektdaten an der Konsole ausgegeben.


' ----------------------------------------------------------
' Beispiel: ...\Kapitel 13\BinaryFormatter
' ----------------------------------------------------------
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Module Module1
Dim binFormatter As _
Runtime.Serialization.Formatters.Binary.BinaryFormatter
Dim myStream As FileStream
Sub Main()
binFormatter = _
New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
Dim obj As ClassA = New ClassA(310, "Peter")
SerializeObject(obj)
Dim oldObj As ClassA = DeserializeObject()
Console.WriteLine("Ergebnis der Deserialisierung:")
Console.WriteLine(oldObj.intVar)
Console.WriteLine(oldObj.Name)
End Sub
' Objekt serialisieren
Public Sub SerializeObject(ByVal obj As Object)
myStream = New FileStream("C:\MyObject.dat", _
FileMode.Create)
binFormatter.Serialize(myStream, obj)
myStream.Close()
End Sub
' deserialisieren
Public Function DeserializeObject() As ClassA
Dim fs As FileStream = _
New FileStream("C:\MyObject.dat", FileMode.Open)
Return binFormatter.Deserialize(fs)
End Function
End Module
<Serializable()> Public Class ClassA
Public intVar As Integer
Private strName As String
Public Sub New(ByVal x As Integer, ByVal str As String)
intVar = x
strName = str
End Sub
Public Property Name() As String
Get
Return strName
End Get
Set(ByVal value As String)
strName = value
End Set
End Property
End Class

Die Ausgabe des Programms lautet:


310
Peter

Serialisierung mehrerer Objekte

Natürlich können mit einem Serialisierungsprozess auch beliebig viele, auch typunterschiedliche Objekte serialisiert werden. Dazu muss man für jedes Objekt Serialize auf demselben Stream-Objekt aufrufen. Die formatierten Daten werden entsprechend der Aufrufreihenfolge serialisiert.

Die Deserialisierung erfolgt in gleicher Weise: Es wird auf demselben Stream-Objekt so lange Deserialize aufgerufen, bis der Datenstrom versiegt. Das Lesen über das Ende des Datenstroms hinaus hat eine Ausnahme zur Folge. Allerdings muss dabei die Reihenfolge beachtet werden, in der die Objekte serialisiert worden sind, denn die Deserialisierung mehrerer Objekte folgt dem FIFO-Prinzip: Das zuerst serialisierte Objekt muss auch als erstes wieder deserialisiert werden.

Für jedes einzelne Objekt Serialize aufzurufen, kann sehr arbeitsaufwändig sein. Außerdem muss die Anzahl der zu serialisierenden Objekte bekannt sein. Ist die Anzahl nicht vorhersehbar, muss ein anderer Weg beschritten werden. Es bietet sich dann an, alle Objekte in einer Objektauflistung zu verwalten und mit einem einzigen Serialize-Aufruf die gesamte Collection in den Datenstrom zu schreiben. Im folgenden Beispielprogramm wird das an vier Objekten unterschiedlichen Typs demonstriert. Sehen wir uns jedoch zuerst den Programmcode an.


' ----------------------------------------------------------
' Beispiel ...\Kapitel 13\CollectionSerialization
' ----------------------------------------------------------
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization
Module Module1
Sub Main()
Dim arrList As New ArrayList
Dim obj1 As ClassA = New ClassA(2334, "Freddy")
Dim obj2 As ClassA = New ClassA(13, "Beate")
Dim pers1 As Person = New Person("Tollsoft")
Dim pers2 As Person = New Person("Microsoft")
' Objekte einer ArrayList übergeben
arrList.Add(obj1)
arrList.Add(obj2)
arrList.Add(pers1)
arrList.Add(pers2)
' ArrayList-Objekt serialisieren
SaveObject(arrList)
Dim newArrList As New ArrayList
' Deserialisieren und die Objektdaten anzeigen
GetObject(newArrList)
Dim obj As Object
For Each obj In newArrList
If (TypeOf obj Is ClassA) Then
Console.Write("{0}/", obj.intVar)
Console.WriteLine(obj.Name)
ElseIf (TypeOf obj Is Person) Then
Console.WriteLine(obj.Name)
End If
Next
Console.ReadLine()
End Sub
' ArrayList-Objekt speichern
Public Sub SaveObject(ByVal arr As ArrayList)
Dim fs As FileStream = _
New FileStream("C:\Objektliste.ifn", FileMode.Create)
Dim binFormatter As BinaryFormatter = New BinaryFormatter()
binFormatter.Serialize(fs, arr)
fs.Close()
End Sub
' Datei lesen und das ArrayList-Objekt in den Referenzpa-rameter
' schreiben – der Rückgabewert gibt Aufschluss über den
' Erfolg der Deserialisierung
Public Sub GetObject(ByRef arr As ArrayList)
Dim fs As FileStream = _
New FileStream("C:\Objektliste.ifn", FileMode.Open)
Try
Dim binFormatter As BinaryFormatter = _
New BinaryFormatter
arr = binFormatter.Deserialize(fs)
Catch e As SerializationException
' die Datei kann nicht deserialisiert werden
Console.WriteLine(e.Message)
Catch e As IOException
' ein Fehler ist beim Versuch des Öffnens der Datei aufgetreten
Console.WriteLine(e.Message)
End Try
End Sub
End Module
' serialisierbare Klassen
<Serializable()> Class ClassA
public intVar as Integer
Private strName As String
Public Sub New(ByVal x As Integer, ByVal str As String)
intVar = x
strName = str
End Sub
Public Property Name() As String
Get
Return strName
End Get
Set(ByVal value As String)
strName = value
End Set
End Property
End Class
<Serializable()> Class Person
Public Name As String
Public Sub New(ByVal str As String)
Name = str
End Sub
End Class

Als Typen sind die beiden Klassen Person und ClassA mit je einem Konstruktor definiert, dem die Werte die Initialisierungswerte übergeben werden. Um sicherzustellen, dass Objekte der beiden Klassen serialisierbar sind, ist den Klassendefinitionen das Attribut Serializable angeheftet.

Der benutzerdefinierten Methode SaveObject kommt die Aufgabe der Objektserialisierung zu. Sie empfängt per Definition im Parameter arr die Referenz auf ein Objekt vom Typ ArrayList, die ebenfalls mit dem Attribut Serializable gekennzeichnet ist.

Die Entscheidung für eine Collection hat zwei Vorteile: Wir brauchen nicht jedes Mitgliedsobjekt der Auflistung einzeln zu serialisieren, sondern können mit einem einzigen Aufruf von Serialize unter Übergabe der ArrayList-Referenz automatisch jedes Objekt in den Datenstrom schreiben. Außerdem kann diese Collection unterschiedliche Typen verwalten.


binFormatter.Serialize(fs, arr)

GetObject liefert die Referenz auf das deserialisierte ArrayList-Objekt über den Parameter arr an den Aufrufer zurück, der seinerseits in der Pflicht steht, die Daten der einzelnen Listenobjekte abzufragen. Beachten Sie, dass nur ein Deserialize-Aufruf notwendig ist, um die Daten aller von der Collection verwalteten Objekte wieder zu erhalten.

Um SaveObject und GetObject zu testen, werden in der Routine Main insgesamt vier Objekte erzeugt – jeweils zwei von Person und ClassA. Diese Objekte werden anschließend zu Elementen des ArrayList-Objekts arrList.

Um uns vom Erfolg zu überzeugen, wird ein zweites Objekt vom Typ ArrayList erzeugt, dem die deserialisierten Objekte zugewiesen werden. Die Auflistung wird in einer For Each-Schleife Element für Element durchlaufen und der Typ der aktuellen Referenz mit dem TypeOf-Is-Operator ermittelt.

Daten als nichtserialisierbar kennzeichnen

Mit dem Attribut Serializable werden alle Instanzfelder einer Klasse serialisiert. Das mag im Einzelfall aber nicht immer wünschenswert sein. Eigenschaften, die der Serialisierungsprozess nicht erfassen soll, können durch das Setzen des Attributs NonSerialized vor der Deklaration ausgeschlossen werden.


<Serializable()> Class ClassA
Public intVar As Integer
' das Feld strProp wird nicht serialisiert
<NonSerialized()> Public strProps As String
...
End Class

Das Codefragment enthält die Klassendefinition der Felder intVar und strProp. Beide würden normalerweise während der Serialisierung abgegriffen. Der Deklaration der Instanzvariablen strProp ist allerdings NonSerialized markiert und entzieht strProp dem Serialisierungsprozess.

Serialisierung in einer abgeleiteten Klasse

Das Serializable-Attribut wird nicht vererbt. Wenn Sie also eine serialisierbare Klasse ClassA entwickeln und daraus die Klasse ClassB ableiten, muss das Attribut selbst dann mit ClassB verknüpft werden, wenn nur die aus ClassA geerbten Mitglieder serialisiert werden sollen. Ansonsten gilt die Subklasse als nicht serialisierbar.

Sollen die Felder der Klasse ClassB, die aus ClassA abgeleitet ist, serialisiert werden, muss auch die Basisklasse mit dem Serializable-Attribut verknüpft sein.

 <<   zurück
  
  Zum Katalog
Zum Katalog: Visual Basic 2005
Visual Basic 2005
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Visual C# 2005






 Visual C# 2005


Zum Katalog: Fortgeschrittene Programmierung mit Visual C# 2005






 Fortgeschrittene
 Programmierung
 mit Visual C# 2005


Zum Katalog: Das Programmierhandbuch SQL Server 2005






 Das Programmier-
 handbuch
 SQL Server 2005


Zum Katalog: Einstieg in Visual Basic 2005






 Einstieg in
 Visual Basic 2005


Zum Katalog: Einstieg in Visual C# 2005






 Einstieg in
 Visual C# 2005


Zum Katalog: Konzepte und Lösungen für Microsoft-Netzwerke






 Konzepte und
 Lösungen für
 Microsoft-Netzwerke


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo








Copyright © Galileo Press 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de